home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / fstab.py < prev    next >
Encoding:
Python Source  |  2008-10-08  |  6.2 KB  |  199 lines

  1. # fstab.py - read, manipulate, and write /etc/fstab files
  2. # Copyright (C) 2008  Canonical, Ltd.
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, version 3 of the License.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  15.  
  16.  
  17. import os
  18. import re
  19. import tempfile
  20.  
  21.  
  22. class Line(object):
  23.  
  24.     """A line in an /etc/fstab line.
  25.  
  26.     Lines may or may not have a filesystem specification in them. The
  27.     has_filesystem method tells the user whether they do or not; if they
  28.     do, the attributes device, directory, fstype, options, dump, and
  29.     fsck contain the values of the corresponding fields, as instances of
  30.     the sub-classes of the LinePart class. For non-filesystem lines,
  31.     the attributes have the None value.
  32.     
  33.     Lines may or may not be syntactically correct. If they are not,
  34.     they are treated as as non-filesystem lines.
  35.     
  36.     """
  37.  
  38.     # Lines split this way to shut up coverage.py.
  39.     attrs = ("ws1", "device", "ws2", "directory", "ws3", "fstype")
  40.     attrs += ("ws4", "options", "ws5", "dump", "ws6", "fsck", "ws7")
  41.  
  42.     def __init__(self, raw):
  43.         self.dict = {}
  44.         self.raw = raw
  45.  
  46.     def __getattr__(self, name):
  47.         if name in self.dict:
  48.             return self.dict[name]
  49.         else:
  50.             raise AttributeError(name)
  51.  
  52.     def __setattr__(self, name, value):
  53.         forbidden = ("dict", "dump", "fsck", "options")
  54.         if name not in forbidden and name in self.dict:
  55.             if self.dict[name] is None:
  56.                 raise Exception("Cannot set attribute %s when line dies not "
  57.                                 "contain filesystem specification" % name)
  58.             self.dict[name] = value
  59.         else:
  60.             object.__setattr__(self, name, value)
  61.  
  62.     def get_dump(self):
  63.         return int(self.dict["dump"])
  64.     
  65.     def set_dump(self, value):
  66.         self.dict["dump"] = str(value)
  67.  
  68.     dump = property(get_dump, set_dump)
  69.     
  70.     def get_fsck(self):
  71.         return int(self.dict["fsck"])
  72.  
  73.     def set_fsck(self, value):
  74.         self.dict["fsck"] = str(value)
  75.             
  76.     fsck = property(get_fsck, set_fsck)
  77.  
  78.     def get_options(self):
  79.         return self.dict["options"].split(",")
  80.             
  81.     def set_options(self, list):
  82.         self.dict["options"] = ",".join(list)
  83.         
  84.     options = property(get_options, set_options)
  85.             
  86.     def set_raw(self, raw):
  87.         pat = r"^(?P<ws1>\s*)"
  88.         pat += r"(?P<device>\S+)"
  89.         pat += r"(?P<ws2>\s+)"
  90.         pat += r"(?P<directory>\S+)"
  91.         pat += r"(?P<ws3>\s+)"
  92.         pat += r"(?P<fstype>\S+)"
  93.         pat += r"(?P<ws4>\s+)"
  94.         pat += r"(?P<options>\S+)"
  95.         pat += r"(?P<ws5>\s+)"
  96.         pat += r"(?P<dump>\d+)"
  97.         pat += r"(?P<ws6>\s+)"
  98.         pat += r"(?P<fsck>\d+)"
  99.         pat += r"(?P<ws7>\s*)$"
  100.  
  101.         match = re.match(pat, raw)
  102.         if match:
  103.             self.dict.update((attr, match.group(attr)) for attr in self.attrs)
  104.         else:
  105.             self.dict.update((attr, None) for attr in self.attrs)
  106.         self.dict["raw"] = raw
  107.  
  108.     def get_raw(self):
  109.         if self.has_filesystem():
  110.             return "".join(self.dict[attr] for attr in self.attrs)
  111.         else:
  112.             return self.dict["raw"]
  113.         
  114.     raw = property(get_raw, set_raw)
  115.  
  116.     def has_filesystem(self):
  117.         """Does this line have a filesystem specification?"""
  118.         return self.device is not None
  119.  
  120.  
  121. class Fstab(object):
  122.  
  123.     """An /etc/fstab file."""
  124.  
  125.     def __init__(self):
  126.         self.lines = []
  127.     
  128.     def open_file(self, filespec, mode):
  129.         if type(filespec) in (str, unicode):
  130.             return file(filespec, mode)
  131.         else:
  132.             return filespec
  133.  
  134.     def close_file(self, f, filespec):
  135.         if type(filespec) in (str, unicode):
  136.             f.close()
  137.  
  138.     def get_perms(self, filename):
  139.         return os.stat(filename).st_mode # pragma: no cover
  140.  
  141.     def chmod_file(self, filename, mode):
  142.         os.chmod(filename, mode) # pragma: no cover
  143.  
  144.     def link_file(self, oldname, newname):
  145.         if os.path.exists(newname):
  146.             os.remove(newname)
  147.         os.link(oldname, newname)
  148.  
  149.     def rename_file(self, oldname, newname):
  150.         os.rename(oldname, newname) # pragma: no cover
  151.     
  152.     def read(self, filespec):
  153.         """Read in a new file.
  154.         
  155.         If filespec is a string, it is used as a filename. Otherwise
  156.         it is used as an open file.
  157.         
  158.         The existing content is replaced.
  159.         
  160.         """
  161.         
  162.         f = self.open_file(filespec, "r")
  163.         lines = []
  164.         for line in f:
  165.             lines.append(Line(line))
  166.         self.lines = lines
  167.         self.close_file(filespec, f)
  168.  
  169.     def write(self, filespec):
  170.         """Write out a new file.
  171.         
  172.         If filespec is a string, it is used as a filename. Otherwise
  173.         it is used as an open file.
  174.         
  175.         """
  176.         
  177.         if type(filespec) in (str, unicode):
  178.             # We create the temporary file in the directory (/etc) that the
  179.             # file exists in. This is so that we can do an atomic rename
  180.             # later, and that only works inside one filesystem. Some systems
  181.             # have /tmp and /etc on different filesystems, for good reasons,
  182.             # and we need to support that.
  183.             dirname = os.path.dirname(filespec)
  184.             prefix = os.path.basename(filespec) + "."
  185.             fd, tempname = tempfile.mkstemp(dir=dirname, prefix=prefix)
  186.             os.close(fd)
  187.         else:
  188.             tempname = filespec
  189.     
  190.         f = self.open_file(tempname, "w")
  191.         for line in self.lines:
  192.             f.write(line.raw)
  193.         self.close_file(filespec, f)
  194.  
  195.         if type(filespec) in (str, unicode):
  196.             self.chmod_file(tempname, self.get_perms(filespec))
  197.             self.link_file(filespec, filespec + ".bak")
  198.             self.rename_file(tempname, filespec)
  199.